home *** CD-ROM | disk | FTP | other *** search
/ Best of Shareware / Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso / mac / ZIPPED / DOS / GRAPHICS / RAYSH386.ZIP / SRC / SPHERE.C < prev    next >
C/C++ Source or Header  |  1991-07-18  |  5KB  |  243 lines

  1. /*
  2.  * sphere.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: sphere.c,v 4.0 91/07/17 14:39:17 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    sphere.c,v $
  19.  * Revision 4.0  91/07/17  14:39:17  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23. #include "geom.h"
  24. #include "sphere.h"
  25.  
  26. static Methods *iSphereMethods = NULL;
  27. static char sphereName[] = "sphere";
  28.  
  29. unsigned long SphTests, SphHits;
  30.  
  31. /*
  32.  * Create & return reference to a sphere.
  33.  */
  34. Sphere *
  35. SphereCreate(r, pos)
  36. Float r;
  37. Vector *pos;
  38. {
  39.     Sphere *sphere;
  40.  
  41.     if (r < EPSILON) {
  42.         RLerror(RL_WARN, "Degenerate sphere.\n");
  43.         return (Sphere *)NULL;
  44.     }
  45.  
  46.     sphere = (Sphere *)share_malloc(sizeof(Sphere));
  47.     /*
  48.      * sphere->rsq holds the square of the radius.
  49.      */
  50.     sphere->r = r;
  51.     sphere->rsq = r*r;
  52.     sphere->x = pos->x;
  53.     sphere->y = pos->y;
  54.     sphere->z = pos->z;
  55.  
  56.     return sphere;
  57. }
  58.  
  59. Methods *
  60. SphereMethods()
  61. {
  62.     if (iSphereMethods == (Methods *)NULL) {
  63.         iSphereMethods = MethodsCreate();
  64.         iSphereMethods->create = (GeomCreateFunc *)SphereCreate;
  65.         iSphereMethods->methods = SphereMethods;
  66.         iSphereMethods->name = SphereName;
  67.         iSphereMethods->intersect = SphereIntersect;
  68.         iSphereMethods->normal = SphereNormal;
  69.         iSphereMethods->uv = SphereUV;
  70.         iSphereMethods->enter = SphereEnter;
  71.         iSphereMethods->bounds = SphereBounds;
  72.         iSphereMethods->stats = SphereStats;
  73.         iSphereMethods->checkbounds = TRUE;
  74.         iSphereMethods->closed = TRUE;
  75.     }
  76.     return iSphereMethods;
  77. }
  78.  
  79. /*
  80.  * Ray/sphere intersection test.
  81.  */
  82. int
  83. SphereIntersect(sph, ray, mindist, maxdist)
  84. Sphere *sph;
  85. Ray *ray;
  86. Float mindist, *maxdist;
  87. {
  88.     Float xadj, yadj, zadj;
  89.     Float b, t, s;
  90.  
  91.     SphTests++;
  92.     /*
  93.      * Translate ray origin to object space and negate everything.
  94.      * (Thus, we translate the sphere into ray space, which saves
  95.      * us a couple of negations below.)
  96.      */
  97.     xadj = sph->x - ray->pos.x;
  98.     yadj = sph->y - ray->pos.y;
  99.     zadj = sph->z - ray->pos.z;
  100.  
  101.     /*
  102.      * Solve quadratic equation.
  103.      */
  104.     b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z;
  105.     t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + sph->rsq;
  106.     if (t < 0.)
  107.         return FALSE;
  108.     t = (Float)sqrt((double)t);
  109.     s = b - t;
  110.     if (s > mindist) {
  111.         if (s < *maxdist) {
  112.             *maxdist = s;
  113.             SphHits++;
  114.             return TRUE;
  115.         }
  116.         return FALSE;
  117.     }
  118.     s = b + t;
  119.     if (s > mindist && s < *maxdist) {
  120.         *maxdist = s;
  121.         SphHits++;
  122.         return TRUE;
  123.     }
  124.     return FALSE;
  125. }
  126.  
  127. /*
  128.  * Compute normal to sphere at pos
  129.  */
  130. int
  131. SphereNormal(sphere, pos, nrm, gnrm)
  132. Sphere *sphere;
  133. Vector *pos, *nrm, *gnrm;
  134. {
  135.     nrm->x = (pos->x - sphere->x) / sphere->r;
  136.     nrm->y = (pos->y - sphere->y) / sphere->r;
  137.     nrm->z = (pos->z - sphere->z) / sphere->r;
  138.     *gnrm = *nrm;
  139.     return FALSE;
  140. }
  141.  
  142. /*
  143.  * Determine if ray enters (TRUE) or leaves (FALSE) sphere at pos
  144.  */
  145. int
  146. SphereEnter(sphere, ray, mind, hitd)
  147. Sphere *sphere;
  148. Ray *ray;
  149. Float mind, hitd;
  150. {
  151.     Vector pos;
  152.  
  153.     VecAddScaled(ray->pos, mind, ray->dir, &pos);
  154.     pos.x -= sphere->x;
  155.     pos.y -= sphere->y;
  156.     pos.z -= sphere->z;
  157.  
  158.     return dotp(&pos, &pos) > sphere->rsq;
  159. }
  160.  
  161. /*ARGSUSED*/
  162. void
  163. SphereUV(sphere, pos, norm, uv, dpdu, dpdv)
  164. Sphere *sphere;
  165. Vector *pos, *norm, *dpdu, *dpdv;
  166. Vec2d *uv;
  167. {
  168.     Float phi, theta;
  169.     Vector realnorm;
  170.  
  171.     realnorm.x = pos->x - sphere->x;
  172.     realnorm.y = pos->y - sphere->y;
  173.     realnorm.z = pos->z - sphere->z;
  174.     VecNormalize( &realnorm );
  175.     if (realnorm.z > 1.)    /* roundoff */
  176.         phi = PI;
  177.     else if (realnorm.z < -1.)
  178.         phi = 0;
  179.     else
  180.         phi = acos(-realnorm.z);
  181.  
  182.     uv->v = phi / PI;
  183.  
  184.     if (fabs(uv->v) < EPSILON || equal(uv->v, 1.))
  185.         uv->u = 0.;
  186.     else {
  187.         theta = realnorm.x / sin(phi);
  188.         if (theta > 1.)
  189.             theta = 0.;
  190.         else if (theta < -1.)
  191.             theta = 0.5;
  192.         else
  193.             theta = acos(theta) / TWOPI;
  194.  
  195.         if (realnorm.y > 0)
  196.             uv->u = theta;
  197.         else
  198.             uv->u = 1 - theta;
  199.     }
  200.     if (dpdu != (Vector *)0) {
  201.         dpdu->x = -realnorm.y;
  202.         dpdu->y = realnorm.x;
  203.         dpdu->z = 0.;
  204.         (void)VecNormalize(dpdu);
  205.         (void)VecNormCross(&realnorm, dpdu, dpdv);
  206.     }
  207. }
  208.  
  209. void
  210. SphereBounds(s, bounds)
  211. Sphere *s;
  212. Float bounds[2][3];
  213. {
  214.     bounds[LOW][X] = s->x - s->r;
  215.     bounds[HIGH][X] = s->x + s->r;
  216.     bounds[LOW][Y] = s->y - s->r;
  217.     bounds[HIGH][Y] = s->y + s->r;
  218.     bounds[LOW][Z] = s->z - s->r;
  219.     bounds[HIGH][Z] = s->z + s->r;
  220. }
  221.  
  222. char *
  223. SphereName()
  224. {
  225.     return sphereName;
  226. }
  227.  
  228. void
  229. SphereStats(tests, hits)
  230. unsigned long *tests, *hits;
  231. {
  232.     *tests = SphTests;
  233.     *hits = SphHits;
  234. }
  235.  
  236. void
  237. SphereMethodRegister(meth)
  238. UserMethodType meth;
  239. {
  240.     if (iSphereMethods)
  241.         iSphereMethods->user = meth;
  242. }
  243.